/*
 * bsp_NVM3.c
 *
 *  Created on: 2023年6月28日
 *      Author: mcealt_DS
 */


#include "bsp_nvm.h"
#include <stdio.h>
#include <string.h>
#include "nvm3_hal_flash.h"
#include "nvm3_default.h"
#include "nvm3_default_config.h"
#include "app_log.h"
#include "device.h"
#include "device_nvm.h"

/*******************************************************************************
 *******************************   DEFINES   ***********************************
 ******************************************************************************/

// Maximum number of data objects saved
#ifdef CONFIG_NVM_VERSION
#define MAX_OBJECT_COUNT    ENbyKeyDeviceKeyLast
#else
#define MAX_OBJECT_COUNT    ENbylastKeyIndex
#endif

#ifndef MAX_DATA_LEN
#define MAX_DATA_LEN         44                        //TODO:所有设备包括HUB单个Key中data最大的长度
#endif


// Max and min keys for data objects
#define MIN_DATA_KEY  NVM3_KEY_MIN
#define MAX_DATA_KEY  (MIN_DATA_KEY + MAX_OBJECT_COUNT - 1)

// Key of write counter object
#define WRITE_COUNTER_KEY   MAX_OBJECT_COUNT

// Key of delete counter object
#define DELETE_COUNTER_KEY   (WRITE_COUNTER_KEY + 1)

// Use the default nvm3 handle from nvm3_default.h
#define NVM3_DEFAULT_HANDLE nvm3_defaultHandle
/*******************************************************************************
 **************************   LOCAL VARIABLES   ********************************
 ******************************************************************************/

// Buffer for reading from NVM3
//static char buffer[NVM3_DEFAULT_MAX_OBJECT_SIZE];

/*******************************************************************************
 **************************   LOCAL FUNCTIONS   ********************************
 ******************************************************************************/
static void DS_initialise_counters(void)
{
  uint32_t type;
  size_t len;
  Ecode_t err;

  // check if the designated keys contain counters, and initialise if needed.
  err = nvm3_getObjectInfo(NVM3_DEFAULT_HANDLE, WRITE_COUNTER_KEY, &type, &len);
  if ((err != ECODE_NVM3_OK) || (type != NVM3_OBJECTTYPE_COUNTER)) {
    nvm3_writeCounter(NVM3_DEFAULT_HANDLE, WRITE_COUNTER_KEY, 0);
  }

  err = nvm3_getObjectInfo(NVM3_DEFAULT_HANDLE, DELETE_COUNTER_KEY, &type, &len);
  if ((err != ECODE_NVM3_OK) || (type != NVM3_OBJECTTYPE_COUNTER)) {
    nvm3_writeCounter(NVM3_DEFAULT_HANDLE, DELETE_COUNTER_KEY, 0);
  }
}

void DS_nvm_init_def(void)
{
  Ecode_t err;

   // This will call nvm3_open() with default parameters for
   // memory base address and size, cache size, etc.
   err = nvm3_initDefault();
   EFM_ASSERT(err == ECODE_NVM3_OK);

   // Initialise the counter objects to track writes and deletes.
   DS_initialise_counters();

}


//#define NVM3_BASE_ADDRESS     0x0807a000
//#define NVM3_NVM_SIZE         0x40000
//#define NVM3_CACHE_SIZE       200
//#define NVM3_MAX_OBJECT_SIZE  254
//#define NVM3_REPACK_HEADROOM  0

#if (NVM3_CACHE_SIZE != 0)
static nvm3_CacheEntry_t Cache[NVM3_CACHE_SIZE];
#endif

nvm3_Handle_t  nvm3_HandleData;

NVM_ERR_E DS_nvmInit(void)
{
  Ecode_t err;

  //err = nvm3_open(&nvm3_HandleData, &nvm3_InitData);
  err = nvm3_initDefault();
  if(ECODE_NVM3_OK != err)
    return NVM_ERR_INIT;

  DS_initialise_counters();
  return NVM_OK;
}

NVM_ERR_E DS_nvmDeinit(void)
{
    Ecode_t err = nvm3_deinitDefault();
    if ( err!= ECODE_NVM3_OK )
        return NVM_ERR_DEINIT; 
    return NVM_OK; 
}

NVM_ERR_E DS_nvmDelete(uint32_t key)
{
// Ecode_t err;
 if (key > MAX_DATA_KEY) {
    DS_app_log_error("Invalid key,key=%ld\r\n",key);
    return NVM_ERR_KEY;
  }

  if (ECODE_NVM3_OK == nvm3_deleteObject(NVM3_DEFAULT_HANDLE, key)) {
    // Track number or deletes in counter object
    nvm3_incrementCounter(NVM3_DEFAULT_HANDLE, DELETE_COUNTER_KEY, NULL);
  } else {
    DS_app_log_error("Error deleting key=%ld\r\n",key);
    return NVM_ERR_DELETE;
  }
  return NVM_OK;
}

NVM_ERR_E DS_nvmWrite(uint32_t key, void *value, uint32_t len)
{
  Ecode_t err;
  if (key > MAX_DATA_KEY) {
    DS_app_log_error("Invalid key,key=%ld\r\n",key);
    return NVM_ERR_KEY;
  }

  err = nvm3_writeData(NVM3_DEFAULT_HANDLE,
                        key,
                        (unsigned char *)value,
                        len);
  if (ECODE_NVM3_OK == err)
    {// Track number of writes in counter object
      nvm3_incrementCounter(NVM3_DEFAULT_HANDLE, WRITE_COUNTER_KEY, NULL);
    }
    else{
        DS_app_log_error("Error storing data\r\n");
        return NVM_ERR_DELETE;
    }
        
    return NVM_OK;
}
NVM_ERR_E DS_nvmRead(uint32_t key, void *value, size_t len)
{
  uint32_t type;
  Ecode_t err;

  if (key > MAX_DATA_KEY) {
    DS_app_log_error("Invalid key=%ld\r\n",key);
    return NVM_ERR_KEY;
  }

  err = nvm3_getObjectInfo(NVM3_DEFAULT_HANDLE, key, &type, &len);
  if (err != NVM3_OBJECTTYPE_DATA || type != NVM3_OBJECTTYPE_DATA) {
    if(key != 15 ){
#ifdef HUB_DEVICE
      DS_app_log_debug("Key does not contain data object,key=%ld,type=%ld\r\n",
                           key,type);
#else
      #ifdef  CONFIG_NVM_VERSION
      if(key != ENbyKeyRfmId)
      #endif
      DS_app_log_error("Key does not contain data object,key=%ld,type=%ld\r\n",
                         key,type);

#endif
    }
    return NVM_ERR_KEY;
  }

  err = nvm3_readData(NVM3_DEFAULT_HANDLE, key, value, len);
  if (ECODE_NVM3_OK != err) 
  {
    DS_app_log_error("Error reading data from key %lu\r\n", key);
    return NVM_ERR_READ;
  }
  else
    return NVM_OK;
}

NVM_ERR_E DS_nvmReadOfs(uint32_t key, void *value, size_t len,size_t ofs)
{
//  uint32_t type;
  Ecode_t err;

  if (key > MAX_DATA_KEY) {
    DS_app_log_error("Invalid key=%ld\r\n",key);
    return NVM_ERR_KEY;
  }
#if 0
  err = nvm3_getObjectInfo(NVM3_DEFAULT_HANDLE, key, &type, &len);
  if (err != NVM3_OBJECTTYPE_DATA || type != NVM3_OBJECTTYPE_DATA) {
      DS_app_log_error("Key does not contain data object,key=%ld,type=%ld\r\n",
                         key,type);

    return NVM_ERR_KEY;
  }
  DS_app_log_error("ReadOfs len=%d\n",len);
#endif
  err = nvm3_readPartialData(NVM3_DEFAULT_HANDLE, key, value, ofs,len);
  if (ECODE_NVM3_OK != err)
  {
    //DS_app_log_error("Error reading data from key %lu,ret=0x%lx\r\n", key,err);
    return NVM_ERR_READ;
  }
  else
    return NVM_OK;
}
NVM_ERR_E DS_nvmWriteOfsWithPackLen(uint32_t key, void *value, uint32_t len,size_t ofs,size_t pack_len)
{
  Ecode_t err;

  char buff[MAX_DATA_LEN];

  if (key > MAX_DATA_KEY) {
    DS_app_log_error("Invalid key,key=%ld\r\n",key);
    return NVM_ERR_KEY;
  }

  if(pack_len < len){
      //TODO:超出pack的长度
      DS_app_log_error("pack_len[%d]<len[%ld]\n",pack_len,len);
      return NVM_ERR_KEY;
  }
  if(pack_len > MAX_DATA_LEN){
      DS_app_log_error("!!!MAX_DATA_LEN[%d] < %d\n",MAX_DATA_LEN,pack_len);
      return NVM_ERR_KEY;
  }
  if((ofs+len) > pack_len){
      DS_app_log_error("nvm ofs[%d]+[%ld] > len[%d]\n",ofs,len,pack_len);
      return NVM_ERR_KEY;
  }
  err = nvm3_readData(NVM3_DEFAULT_HANDLE, key, buff, pack_len);
  if (ECODE_NVM3_OK != err)
  {
      memset(buff,0,sizeof(buff));
  }

  memcpy(&buff[ofs],(unsigned char *)value,len);
  //
  err = nvm3_writeData(NVM3_DEFAULT_HANDLE,
                        key,
                        (unsigned char *)buff,
                        pack_len);
  if (ECODE_NVM3_OK == err)
    {// Track number of writes in counter object
      nvm3_incrementCounter(NVM3_DEFAULT_HANDLE, WRITE_COUNTER_KEY, NULL);
    }
    else{
        DS_app_log_error("Error storing data\r\n");
        return NVM_ERR_DELETE;
    }

    return NVM_OK;
}
NVM_ERR_E DS_nvmWriteWithLen(uint32_t key, void *value)
{
  Ecode_t err;
  size_t len;
  uint32_t type;

  if (key > MAX_DATA_KEY) {
    DS_app_log_error("Invalid key,key=%ld\r\n",key);
    return NVM_ERR_KEY;
  }

  err = nvm3_getObjectInfo(NVM3_DEFAULT_HANDLE, key, &type, &len);
  if (err != NVM3_OBJECTTYPE_DATA || type != NVM3_OBJECTTYPE_DATA) {
      DS_app_log_debug("Key does not contain data object,key=%ld,type=%ld\r\n",
                           key,type);

    return NVM_ERR_KEY;
  }

  err = nvm3_writeData(NVM3_DEFAULT_HANDLE,
                        key,
                        (unsigned char *)value,
                        len);
  if (ECODE_NVM3_OK == err)
    {// Track number of writes in counter object
      nvm3_incrementCounter(NVM3_DEFAULT_HANDLE, WRITE_COUNTER_KEY, NULL);
    }
    else{
        DS_app_log_error("Error storing data\r\n");
        return NVM_ERR_DELETE;
    }

    return NVM_OK;
}
NVM_ERR_E DS_nvmReset(void)
{
  Ecode_t err;
  DS_app_log_error("Deleting all data stored in NVM3\r\n");
  err = nvm3_eraseAll(NVM3_DEFAULT_HANDLE);
  // This deletes the counters, too, so they must be re-initialised
  DS_initialise_counters();
  if (ECODE_NVM3_OK != err) 
    return NVM_ERR_READ;
  else
    return NVM_OK;
}

